/*
 * Persona.cpp
 *
 *  Created on: May 6, 2012
 *
 */
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>
#include "Persona.h"
#include "../lib/Util.h"

#define PROCESS_NAME "PERSONA"

using namespace std;

void Persona::log(string message) {
	string name = PROCESS_NAME;
	string msg = name + ": " + message;
	logger->loggearLog(msg);
}

void Persona::sync(string message) {
	string name = PROCESS_NAME;
	string msg = name + ": " + message;
	logger->loggearSynchro(msg);
}

void Persona::debug(string message) {
	string name = PROCESS_NAME;
	string msg = name + ": " + message;
	logger->loggearDebug(msg);
}

Persona::Persona(int cantidad_pisos, int cantidad_asc, int capacidad,
		int velocidad, bool modoDebug, bool modoLog, bool modoSyn,
		bool modoCout) {
	Logger::getInstance()->setFlags(modoDebug, modoLog, modoSyn, modoCout);	
	this->logger = Logger::getInstance();

	this->m_pisos = new MonitorPisos(cantidad_pisos);
	this->sem_pisos = new ManejadorSemPisos(cantidad_pisos);
	this->m_asc = new MonitorAscensores(cantidad_asc, cantidad_pisos, capacidad,
			velocidad);
	this->sem_asc = new ManejadorSemAscensores(cantidad_asc);
	this->cantidad_pisos = cantidad_pisos;
	this->inicializar();
}

void Persona::inicializar() {

	this->setPisoDestino(0);
	this->setPisoOrigen(0);
	this->calcularPeso();
	this->calcularPisoOrigen();
	this->calcularPisoDestino();

	/*Codigo para forzar la aparicion de piso_origen = 0 o
	 *piso_destino = 0 y agregar realidad a la simulacion
	 */
	srand(time(NULL));
	int random_numero = rand();
	if (0 == random_numero % 3 && this->getPisoOrigen() != 0)
		this->setPisoDestino(0);
	else if (1 == random_numero % 2 && this->getPisoDestino() != 0)
		this->setPisoOrigen(0);
	while (this->getPisoOrigen() == this->getPisoDestino())
		this->calcularPisoDestino();
	/***/

	if (this->mi_piso_destino > this->mi_piso_origen)
		this->mi_estado = ESPERANDO_SUBIR;
	else
		this->mi_estado = ESPERANDO_BAJAR;

	this->apuntarme();
	char st[512];

	sprintf(st, "Naci! Peso: %d, Origen: %d, Destino: %d", this->getPeso(),
			this->getPisoOrigen(), this->getPisoDestino());
	this->log(st);
}

void Persona::calcularPeso() {
	this->setPeso(PESO_PROMEDIO);
}

void Persona::calcularPisoOrigen() {
	srand(time(NULL));
	int resultado = rand() % this->cantidad_pisos;
	this->setPisoOrigen(resultado);
}

void Persona::calcularPisoDestino() {
	srand(time(NULL));
	int resultado = rand() % this->cantidad_pisos;
	this->setPisoDestino(resultado);
}

int Persona::estabaBajando() {
	if (this->mi_estado == ESPERANDO_BAJAR)
		return this->cantidad_pisos;
	else
		return 0;
}

bool Persona::apuntarme() {
	this->m_pisos->incrementar(this->getPisoOrigen(), this->mi_estado);
	this->debug("Ya estoy esperando al ascensor.");
	return true;
}

int Persona::llamarAscensorYEsperar() {

	int mi_asc = -1;
	this->log("Llamo al ascensor y espero.");
	while (1) {

		/*Cuando estoy afuera*/
		this->sem_pisos->esperoAscensor(this->getPisoOrigen(),
				this->mi_estado);

		/*Cuando estoy adentro*/
		mi_asc = this->m_asc->subir(this->getPeso(), this->getPisoOrigen(),
				this->getPisoDestino());

		this->sem_pisos->esperoCierre(this->getPisoOrigen(),
				this->mi_estado);

		if (mi_asc != -1) {
			this->log(
					"Al fin me subi al ascensor " + Util::intToString(mi_asc));
			break;
		}
	}

	while (1) {
		/*Cuando me bajo*/
		this->sem_asc->esperarApertura(mi_asc);
		this->debug("Termine de esperar Apertura.");

		tascensor asc = this->m_asc->leer(mi_asc);

		if (asc.pisoActual == this->getPisoDestino()) {
			this->m_asc->bajar(mi_asc, this->getPeso());
			this->log("Llegue a mi piso destino.");
			this->sem_asc->habilitarCierre(mi_asc);
			this->log("Chau!");
			return 0;
		} else
			this->debug("El piso al que llego el ascensor no es el mio. Asc =" +
					Util::intToString(asc.pisoActual) + ", Yo ="
					+ Util::intToString(this->getPisoDestino()));

		this->sem_asc->habilitarCierre(mi_asc);
	}
	return 0;
}

Persona::~Persona() {
	delete (this->m_pisos);
	delete (this->sem_pisos);
	delete (this->m_asc);
	delete (this->sem_asc);
}

